import cv2
import numpy as np

############----------这一段代码主要用于检测椭圆形状
###########-----------程序中已经加过注释，程序中的参数值都可以改一下，会有不同的识别效果.
###########-----------程序中已经加过注释，程序中的参数值都可以改一下
def Detect_shapes_2(image,theta):
    # image=cv2.imread(path)
    # 获取图像尺寸
    height, width, _ = image.shape

    # 去除非边缘噪声：使用形态学操作
    kernel = np.ones((5, 5), np.uint8)
    morph_image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    # 将图像转换为灰度图
    gray = cv2.cvtColor(morph_image, cv2.COLOR_BGR2GRAY)

    # # 图像增强：直方图均衡化
    # enhanced_image = cv2.equalizeHist(gray)
    numpy_img = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11,
                                      5)  # 自动阈值二值化
    # 使用Canny边缘检测
    edges = cv2.Canny(gray, 20, 200, apertureSize=3, L2gradient=True)
    #cv2.imshow("mm", edges)
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 过滤小边缘
    min_contour_length = 30  # 设置最小边缘长度阈值
    filtered_contours = [cnt for cnt in contours if cv2.arcLength(cnt, closed=True) > min_contour_length]
    # 新建一个列表，用于存储有效的轮廓
    valid_contours = []
    # 循环检测到的轮廓，去除一些效果不好的轮廓
    for contour in filtered_contours:
        # 拟合椭圆
        if len(contour) >= 400:
            ellipse = cv2.fitEllipse(contour)
            (x, y), (a, b), angle = ellipse
            # 计算椭圆的四个顶点
            box = cv2.boxPoints(ellipse) #cv2.boundingRect(contour)
            ellipse_point = cv2.ellipse2Poly((int(ellipse[0][0]), int(ellipse[0][1])),
                                              (int(ellipse[1][0] / 2), int(ellipse[1][1] / 2)),
                                              int(ellipse[2]), 0, 360,
                                              1)  # 获取椭圆上的点
            # 排除过小的椭圆
            contour_area=cv2.contourArea(contour)
            if contour_area>100 and 1/np.cos(theta)-0.1 < a/b < 1/np.cos(theta)+0.1:
                # 检查椭圆的四个顶点是否都在图像内
                inside = True
                for point in box:
                    if point[0] < 0 or point[0] >= width or point[1] < 0 or point[1] >= height:
                        inside = False
                        break
                if inside:
                    valid_contours.append(contour)
    # Find the contour with the maximum length
    longest_contour = max(valid_contours, key=len)
    ellipse = cv2.fitEllipse(longest_contour)
    # 绘制中心点
    center = (int(ellipse[0][0]), int(ellipse[0][1]))
    #cv2.circle(image, center, 2, (0, 255, 0), -1)
    # cv2.putText(image, str(0), center, cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1)
    cv2.ellipse(image, ellipse, (150, 0, 200), 2)

    return ellipse#, draw_center

############----------接下来的代码是原始可行的代码，注意不要改动，当前面的代码出现问题，可以复制下面的代码使用
###########-----------接下来的代码是原始可行的代码，注意不要改动
###########-----------接下来的代码是原始可行的代码，注意不要改动
"""
def Detect_shapes_2(image,theta):
    # image=cv2.imread(path)
    # 获取图像尺寸
    height, width, _ = image.shape

    # 去除非边缘噪声：使用形态学操作
    kernel = np.ones((5, 5), np.uint8)
    morph_image = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
    # 将图像转换为灰度图
    gray = cv2.cvtColor(morph_image, cv2.COLOR_BGR2GRAY)

    # # 图像增强：直方图均衡化
    # enhanced_image = cv2.equalizeHist(gray)
    numpy_img = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11,
                                      5)  # 自动阈值二值化
    # 使用Canny边缘检测
    edges = cv2.Canny(gray, 20, 200, apertureSize=3, L2gradient=True)
    #cv2.imshow("mm", edges)
    contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    # 过滤小边缘
    min_contour_length = 30  # 设置最小边缘长度阈值
    filtered_contours = [cnt for cnt in contours if cv2.arcLength(cnt, closed=True) > min_contour_length]
    # 新建一个列表，用于存储有效的轮廓
    valid_contours = []
    # 循环检测到的轮廓，去除一些效果不好的轮廓
    for contour in filtered_contours:
        # 拟合椭圆
        if len(contour) >= 400:
            ellipse = cv2.fitEllipse(contour)
            (x, y), (a, b), angle = ellipse
            # 计算椭圆的四个顶点
            box = cv2.boxPoints(ellipse) #cv2.boundingRect(contour)
            ellipse_point = cv2.ellipse2Poly((int(ellipse[0][0]), int(ellipse[0][1])),
                                              (int(ellipse[1][0] / 2), int(ellipse[1][1] / 2)),
                                              int(ellipse[2]), 0, 360,
                                              1)  # 获取椭圆上的点
            # 排除过小的椭圆
            contour_area=cv2.contourArea(contour)
            if contour_area>100 and 1/np.cos(theta)-0.1 < a/b < 1/np.cos(theta)+0.1:
                # 检查椭圆的四个顶点是否都在图像内
                inside = True
                for point in box:
                    if point[0] < 0 or point[0] >= width or point[1] < 0 or point[1] >= height:
                        inside = False
                        break
                if inside:
                    valid_contours.append(contour)
    # Find the contour with the maximum length
    longest_contour = max(valid_contours, key=len)
    '''
    if len(valid_contours)>0:
        # 重新拟合剩余的轮廓
        i = 0 # 显示椭圆的序号
        num_mate=[] #用于存储椭圆与轮廓匹配最多点的数量
        for contour1 in valid_contours:
            ellipse = cv2.fitEllipse(longest_contour)
            #计算椭圆上的点，用于后期匹配点
            num_common = []  # 用于存储匹配点的数量
            ellipse_points = cv2.ellipse2Poly((int(ellipse[0][0]), int(ellipse[0][1])),
                                              (int(ellipse[1][0] / 2), int(ellipse[1][1] / 2)),
                                              int(ellipse[2]), 0, 360,
                                              1)  # 获取椭圆上的点
            point_set = set(tuple(p) for p in ellipse_points)
            # 用计算出的椭圆去匹配轮廓上的点
            for contour2 in valid_contours:
                Contour_point=set()
                for sub_array in contour2:
                    for sub_point in sub_array:
                        Contour_point.add(tuple(sub_point))
                common_element = point_set.intersection(Contour_point)
                num_common.append(len(common_element))
            max_value=max(num_common)
            num_mate.append(max_value)
            # 绘制椭圆
        '''
    ellipse = cv2.fitEllipse(longest_contour)
    # 绘制中心点
    center = (int(ellipse[0][0]), int(ellipse[0][1]))
    #cv2.circle(image, center, 2, (0, 255, 0), -1)
    # cv2.putText(image, str(0), center, cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1)
    cv2.ellipse(image, ellipse, (150, 0, 200), 2)
    #i += 1
        # 绘制轮廓
        #cv2.drawContours(image, valid_contours, -1, (150, 150, 0), 2)
    '''
        # 基于椭圆轨迹与轮廓轨迹的匹配程度来选择一个拟合椭圆
    if max(num_mate)>0:
        max_index=num_mate.index(max(num_mate))
        draw_contour=valid_contours[max_index]
        box = cv2.boundingRect(valid_contours[max_index])
        draw_ellipse=cv2.fitEllipse(draw_contour)
        draw_center=(int(draw_ellipse[0][0]),int(draw_ellipse[0][1]))
        # draw_text = f"  {int(draw_ellipse[0][0])} {int(draw_ellipse[0][1])}"
        cv2.ellipse(image,ellipse,(150,0,200),2)
            # cv2.putText(image, draw_text, draw_center, cv2.FONT_HERSHEY_PLAIN, 1, (150,0,200), 1)
        #cv2.imshow("Ellipses", image)
        #cv2.waitKey(0) # 0为等待键盘命令关闭，如果需要实时检测，需要关闭这两句话
        # cv2.destroyAllWindows()
    '''
    return ellipse#, draw_center
    """